4.1-前后端交互
Create by fall on 27 Dec 2021 Recently revised in 07 Aug 2023
前后端交互
- 原生 ajax
- 基于 jQuery 的 ajax
- fetch (可以理解为 ajax 升级版,也是标准化组织的新一套规范)
- axios (库,更加方便的调用接口)
fetch
基本用法
fetch
用于传输数据时,使用简单,基于 Promise
进行实现,所有除 IE 之外的浏览器都实现了支持
// fetch 会返回一个 Promise 对象 // Promise<Response> fetch(url[,init])
fetch(url).then(res=>{
// 选择 fetch 后的内容的处理方式
return res.text()
// 下面三个方法都是 Promise 对象,存放着处理后的数据
// res.text() 解析为 text
// res.json() 解析为 json
// res.blob() 解析为二进制文件
}).then(result=>{
// 解析后的结果
console.log(result)
})
配置
通过在 url 后面传入 对象,以此来进行配置
// 中可以选择的配置,默认值会用 * 标注
fetch(url, {
method:'get',// 包括 *get post put delete
body: JSON.stringify(data), // 必须匹配 headers 中的 'Content-Type'
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, *omit
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer', // *client, no-referrer
referrerPolicy:'no-referrer', //
})
Body
配置中的 body 内容,可以为以下任一类型
string
ArrayBuffer
ArrayBufferView
(Uint8Array 等)Blob
/File
URLSearchParams
FormData
实例
上传 JSON 数据
const jsonData = {name:'fall',age:23}
// const formData = new FormData()
// formData.push('name','fall')
fetch('http://localhost:2333',{
method:'POST',
formData:{
"Content-Type":'application/json' // 传输 json 必须要设置对应的请求头
},
body:JSON.stringify(jsonData) // 或者直接唇乳上面的 formData
}).then(resopnse=>{
// response.ok 用来判断 http 状态码是否正常
if(!response.ok){
throw new Error('Network response error')
}
// 如果要解析为 JSON,必须保证 Content-Type 为 application/json
const contentType = response.get('Content-Type')
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Oops, we haven't got JSON!");
}
return resopnse.json()
}).then(res=>{
console.log(resopnse)
})
上传文件
const file = new File([''],'file.txt',{type:'text/plain'})
const formData = new FormData()
formData.push('file','file.txt')
fetch('http://localhost:2333',{
method:'POST',
formData:{
"Content-Type":'application/json' // 传输 json 必须要设置对应的请求头
},
body:JSON.stringify(jsonData) // 或者直接传递上面的 formData
}).then(resopnse=>{
return resopnse.json()
}).then(res=>{
console.log(resopnse)
})
请求参数
const searchParams = new URLSearchParams()
searchParams.append('name','刘')
searchParams.toString()
// 使用 ? 进行拼接,服务器只需照常接受数据即可
fetch('http://localhost:3000/books?id=3',{
method:"get"
})
// 服务器端代码
app.get('/books',(req,res)=>{
res.send('请求的传递参数')
})
// 使用 '/' 进行拼接,即restful形式,服务器需要更改数据的接收方式
fetch('http://www.cctv.com/books/id=3',{
method:'get'
})
// 服务器端代码
app.get('/books/:id',(req,res)=>{
res.send('restful形式的url请求传递参数'+req.params.id)
})
post方式传递请求
fetch('/books',{
method:'post',
body:'uname=lisi&pwd=123',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
}
})
// 将数据转化为 json 格式
fetch('/books',{
method:'post',
body:JSON.stringify({
uname=lisi,
pwd=123
}),
headers:{
'Content-Type':'application/json'
}
})
服务器接收post请求
app.use(bodyParser.json())
app.post('/books',(req,res)=>{
res.send('post请求传递参数'+req.body.uname '----'+req.body.pwd)
})
请求相关对象
Fetch
// Default options are marked with *
fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: JSON.stringify(data) // body data type must match "Content-Type" header
})
Headers
请求中的 headers
const headerSetting = new Headers({
'Content-Type': 'text/plain',
'X-Custom-Header': 'ProcessThisImmediately'
})
headerSetting.append("Content-Length",content.length.toString())
// 有这些属性
Headers.prototype.set()
Headers.prototype.get()
Headers.prototype.append()
Headers.prototype.has()
Headers.prototype.delete()
// 如果使用了一个不合法的 HTTP Header 属性名,那么 Headers 的方法通常都抛出 TypeError 异常。
Request
const myHeaders = new Headers()
const myRequest = new Request('flower.jpg',{
method:"GET",
headers:myHeaders,
mode:'cros',
cache:'default'
})
fetch(myRequest).then(response=>response)
Response
Response 对象中实现了一些内容,用于获取 body 中的内容
Response.prototype.text()
Response.prototype.json()
Response.prototype.blob()
Response.prototype.arrayBuffer()
Response.prototype.formData()
fetch 后返回的内容,就是 Response 对象
fetch('http://localhost:3033').then(response=>{
response.status // response 状态码 200
response.ok // 该属性是来检查 response 的状态是否在 200 - 299(包括 200 和 299)这个范围内。
})
URL
URL:统一资源定位符
- 定位符的内容:
协议://主机名(域名):端口号/路径/?查询字符串#锚点
protocol://hostname:port/pathname/?search#hash
- 实例:
https://juejin.cn/post/6960262593265025031#heading-26
(端口号会自动隐藏)
URLSearchParams
const searchParams = new URLSearchParams({dkd:'df'})
searchParams.append('name','lao')
url
查询字符串的变量
FormData
FormData
是当数据进行传输时,填入的类型。
var formData = new FormData();
formData.append("username", "Groucho");
formData.append("accountnum", 123456); //数字 123456 会被立即转换成字符串 "123456"
// HTML 文件类型 input,由用户选择
formData.append("userfile", fileInputElement.files[0]);
// JavaScript file-like 对象
var content = '<a id="a"><b id="b">hey!</b></a>'; // 新文件的正文
var blob = new Blob([content], { type: "text/xml"});
formData.append("webmasterfile", blob);
var request = new XMLHttpRequest();
request.open("POST", "http://foo.com/submitform.php");
request.send(formData);
在 formData.append(key,value)
如果它的 value
字段类型不是 Blob 也不是 File,则会被转换成字符串
axios库
详情请见前端开发工具中关于 axios 的文章
既可以生成一个新的配置,也可以在 axios 的基础上进行配置,这里选择后者。
首先需要配置 axios
axios.defaults.timeout = 5000 // 响应超时时间
axios.defaults.baseURL = 'http://localhost:3000' // 默认基准地址
axios.defaults.headers['mytoken']= 'adacocizuzxoui322ucuzcoiu' // 设置响应头
// 前面会自动添加上 'http://localhost:3000'
// axios.get(url[,init]) init 是一个对象
axios.get({
// params 可以自动将对象数据转换成拼接字符串进行传输
url:"/hello",
params:{
id:233,
date:'2020-02-05'
}
}).then((res)=>{
console.log(res.data)
})
// post 请求
ajax
异步的 javascript 和数据传输
- 同步:一个程序运行时,会堵塞其他程序的使用,等待使用它的程序运行完成后继续运行
- 异步:一个程序运行与否,和另一个程序是否运行没有关系
ajax 是前后端交互的搬运工,在程序执行过程中可以不受干扰的异步进行
使用
- 创建 ajax 对象
- 调用 open
- 第一个参数 : 请求方式:
get
/post
- 第二个参数:
url
- 第三个参数:是否异步:
true
表示异步false
:表示同步
- 第一个参数 : 请求方式:
- 调用 send
- 等待数据响应,响应后执行
onreadystatechange
方法
ajax的实例
//创建ajax对象
var xhr = new XMLHttpRequest()
//调用open
xhr.open("get","1.txt",true)
xhr.send()
xhr.onreadystatechange = function(){ // 当 state 改变后会自动调用该方法
if(xhr.readyState==4){
console.log(xhr.responseText) // 以文本形式存放的内容
console.log(xhr.status) // 服务器(请求资源)的状态
console.log(xhr.responseXML) // 返回 XML 形式的内容
}
}
xhr.readyState值的含义
返回值 | 状态 | 属性 |
---|---|---|
0 | 初始化 | 还没有调用 open() 方法,返回0证明对象存在,否则浏览器报错 |
1 | 载入 | 已经调用 open() 方法,并且调用send方法正在向服务器发送请求 |
2 | 载入完成 | send() 方法完成已经收到全部相应数据,得到的是服务器的原始数据 |
3 | 解析 | 把数据转换成能通过responseBody、responseText或responseXML属性存取的格式,为调用做准备 |
4 | 完成 | 响应内容解析完成,可以在客户端调用 |
兼容问题
var xhr = new XMLHttpRequest()
不兼容IE8以下不兼容
IE8 以下声明 ajax 的方式是
ActiveXObject("Microsoft.XMLHTTP");
var xhr = null
if(window.XMLHttpRequest()){
xhr = new XMLHttpRequest()
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
xhr.open("get","1.txt",true)
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState==4){
alert(xhr.responseText)
}
}
异步的调用
-
异步效果分析
- 定时任务
- Ajax
- 时间函数
-
多次异步调用的依赖分析
- 多次异步调用会因为网络等一系列原因导致顺序不确定
- 如果想要确定的顺序,必须进行嵌套
XMLHttpRequest
- XMLHttpRequest onreadystatechange 处理流程:未初始化 -> OPENED -> HEADERS_RECEIVED -> LOADING -> DONE
- 渲染进程会将请求发送给网络进程,然后网络进程负责资源下载,等网络进程接收到数据后,利用 IPC 通知渲染进程;
- 渲染进程接收到消息之后,会将 xhr 回调函数封装成任务并添加到消息队列中,等主线程循环系统执行到该任务的时候,会根据相关状态来调用回调函数。
WebRTC API
它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC 包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建点对点(Peer-to-Peer)的数据分享和电话会议成为可能。
fetch
Fetch API 是近年来被提及将要取代 XHR 的技术新标准,是一个 HTML5 的 API。 Fetch 并不是 XHR 的升级版本,而是从一个全新的角度来思考的一种设计。Fetch 是基于 Promise 语法结构,而且它的设计足够低阶,这表示它可以在实际需求中进行更多的弹性设计。对于XHR所提供的能力来说,Fetch 已经足够取代 XHR,并且提供了更多拓展的可能性。
// 基本用法,获取 json 资源
fetch('some.json')
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log('data', data);
})
.catch(function(error) {
console.log('Fetch Error: ', error);
});
// 采用ES2016的 async/await 语法
async function() {
try {
const response = await fetch('some.json');
const data = response.json();
console.log('data', data);
} catch (error) {
console.log('Fetch Error: ', error)
}
}
fetch.Post请求
fetch('https://www.api.com/api/xxx', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: 'a=1&b=2',
}).then(resp => resp.json()).then(resp => {
console.log(resp)
});
fetch.Get请求
fetch('https://www.api.com/api/xxx?location=北京&key=bc08513d63c749aab3761f77d74fe820',{
method:'GET'
}) // 返回一个Promise对象
.then((res)=>{
return res.json();
})
.then((res)=>{
console.log(res) // res是最终的结果
})
fetch请求网页
fetch('https://www.api.com/api/xxx')
.then(response => response.text())
.then(data => console.log(data));
自定义header
var headers = new Headers({
"Content-Type": "text/plain",
"X-Custom-Header": "aaabbbccc",
});
var formData = new FormData();
formData.append('name', 'lxa');
formData.append('file', someFile);
var config = {
credentials: 'include', // 支持cookie
headers: headers, // 自定义头部
method: 'POST', // post方式请求
body: formData // post请求携带的内容
};
fetch('https://www.api.com/api/xxx', config)
.then(response => response.json())
.then(data => console.log(data));
// 或者这样添加头部
var content = "Hello World";
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
myHeaders.append("Content-Length", content.length.toString());
myHeaders.append("X-Custom-Header", "ProcessThisImmediately");
fetch其他参数
- method: 请求的方法,例如:GET,POST。
- headers: 请求头部信息,可以是一个简单的对象,也可以是 Headers 类实例化的一个对象。
- body: 需要发送的信息内容,可以是Blob,BufferSource,FormData,URLSearchParams或者USVString。注意,GET,HEAD方法不能包含body。
- mode: 请求模式,分别有cors,no-cors,same-origin,navigate这几个可选值。
- cors: 允许跨域,要求响应中Acess-Control-Allow-Origin这样的头部表示允许跨域。
- no-cors: 只允许使用HEAD,GET,POST方法。
- same-origin: 只允许同源请求,否则直接报错。
- navigate: 支持页面导航。
- credentials: 表示是否发送cookie,有三个选项
- omit: 不发送cookie。
- same-origin: 仅在同源时发送cookie。
- include: 发送cookie。
- cache: 表示处理缓存的策略。
- redirect: 表示发生重定向时,有三个选项
- follow: 跟随。
- error: 发生错误。
- manual: 需要用户手动跟随。
- integrity: 包含一个用于验证资资源完整性的字符串
var URL = 'https://www.api.com/api/xxx';
// 实例化 Headers
var headers = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
var getReq = new Request(URL, {method: 'GET', headers: headers });
fetch(getReq).then(function(response) {
return response.json();
}).catch(function(error) {
console.log('Fetch Error: ', error);
});
参考文章
作者 | 文章名称 |
---|---|
牛客网 | 面试宝典 |
MDN | Fetch |